/*************************************************
 Copyright © DusunIoT 2005-2023. All rights reserved.
 File name: common_thread.c
 Author: yaoyuxi
 Version: V1.0
 Date: Tuesday, July 11, 2023 
 Description: 系统接口统一封装定义
 Others: none
 History: Created July 11, 2023  by:yaoyuxi
*************************************************/
#include <pthread.h>
#include <sys/prctl.h>
#include <string.h>
#include <stdio.h>

#include "common_types.h"
#include "common_dbg_log.h"
#include "common_thread.h"

/**@brief     动态内存申请封装接口函数，开发中所有动态内存使用必须通过该接口进行
* @param[in]  uiMemLen:申请内存大小
* @param[out] 无
* @return     pcMenAdrr:申请内存地址指针
*/
RB_UINT8 * rb_malloc(RB_UINT32 uiMemLen)
{
    RB_UINT8 * pcMenAdrr = RB_NULL;
    
    if (uiMemLen > 0)
    {
        pcMenAdrr = malloc(uiMemLen);
    }

    return pcMenAdrr;
}

/**@brief     获取线程优先级范围，内部接口
* @param[out] piMinThreadPrio:最小优先级
* @param[out] piMaxThreadPrio:最大优先级
* @return     RB_OK:获取优先级范围成功,RB_ERR:线程名字设置失败
*/
static RB_INT32 rb_pthread_get_prio_scope(RB_INT32 *piMinThreadPrio, RB_INT32 *piMaxThreadPrio)
{
    if ((RB_NULL == piMinThreadPrio) || (RB_NULL == piMaxThreadPrio))
    {
        DBG_LOG_ERR("create thread input piMinThreadPrio or piMaxThreadPrio is NULL!");
        return RB_ERR;
    }

    (*piMinThreadPrio) = sched_get_priority_min(SCHED_RR);
    if (RB_ERR != *piMinThreadPrio)
    {
        DBG_LOG_ERR("thread get priority min fail!");
        return RB_ERR;
    }
    
    (*piMaxThreadPrio) = sched_get_priority_max(SCHED_RR);
    if (RB_ERR != *piMaxThreadPrio)
    {
        DBG_LOG_ERR("thread get priority max fail!");
        return RB_ERR;
    }

    DBG_LOG_INFO("thread priority: min = %d, max = %d. \n", *piMinThreadPrio, *piMaxThreadPrio);
    
    return RB_OK;
}

/**@brief     线程创建封装接口函数，开发中所有线程创建必须通过该接口进行
* @param[in]  iThreadPrio:线程优先级控制参数,优先级只支持COMMON_THREAD_PRIO_E中内容
* @param[in]  iThreadStackSize:线程栈默认大小控制参数
* @param[in]  pThreadFunc:线程执行函数指针
* @param[in]  pTreadArg:线程执行函数入参指针，只能有一个入参
* @param[out] stThreadId:线程ID
* @return     iRet:线程创建结果，如果为RB_OK则创建成功，其他返回值为创建失败
*/
RB_INT32 rb_pthread_create(pthread_t *pstThreadId, 
                                RB_INT32 iThreadPrio, 
                                size_t iThreadStackSize, 
                                RB_VOID *pThreadFunc, 
                                RB_VOID *pTreadArg)
{
    RB_INT32 iRet = RB_OK;
    pthread_attr_t stThreadAttr;
    struct sched_param stSchedParams;
    RB_INT32 iMinPriority = COMMON_THREAD_PRIO_MIN;
    RB_INT32 iMaxPriority = COMMON_THREAD_PRIO_MAX;

    if (RB_NULL == pstThreadId)
    {
        DBG_LOG_ERR("create thread input pstThreadId is NULL!");
        return RB_ERR;
    }

    memset(&stThreadAttr, 0, sizeof(stThreadAttr));
    memset(&stSchedParams, 0, sizeof(stSchedParams));
    
    iRet = pthread_attr_init(&stThreadAttr);
    if (RB_OK != iRet)
    {
        DBG_LOG_ERR("thread init fail!");
        return iRet;
    }

    /*使用round robin调度算法*/
    iRet = pthread_attr_setschedpolicy(&stThreadAttr, SCHED_RR);
    if (RB_OK != iRet)
    {
        DBG_LOG_ERR("thread set sched policy is SCHED_RR fail!");
        pthread_attr_destroy(&stThreadAttr);
        return iRet;
    }
   
    /*设置线程为分离状态*/
    iRet = pthread_attr_setdetachstate(&stThreadAttr, PTHREAD_CREATE_DETACHED);
    if (RB_OK != iRet)
    {
        DBG_LOG_ERR("thread set detach state is PTHREAD_CREATE_DETACHED fail!");
        pthread_attr_destroy(&stThreadAttr);
        return iRet;
    }

     /*获取调度参数*/
    iRet = pthread_attr_getschedparam(&stThreadAttr, &stSchedParams);
    if (RB_OK != iRet)
    {
        DBG_LOG_ERR("thread get sched param fail!");
        pthread_attr_destroy(&stThreadAttr);
        return iRet;
    }
    
     /*设置线程优先级*/
    if (iThreadPrio < iMinPriority)
    {
        iThreadPrio = iMinPriority;
    }
    
    if (iThreadPrio > iMaxPriority)
    {
        iThreadPrio = iMaxPriority;
    }
    stSchedParams.sched_priority = iThreadPrio;
    
     /*设置调度参数*/
    iRet = pthread_attr_setschedparam(&stThreadAttr, &stSchedParams);
    if (RB_OK != iRet)
    {
        DBG_LOG_ERR("thread set sched param fail!");
        pthread_attr_destroy(&stThreadAttr);
        return iRet;
    }
    
    if (iThreadStackSize < THREAD_STACK_MIN_VAL)
    {
        iThreadStackSize = THREAD_STACK_MIN_VAL;
    }
    
     /*设置线程栈大小参数*/
    iRet = pthread_attr_setstacksize(&stThreadAttr, iThreadStackSize);
    if (RB_OK != iRet)
    {
        DBG_LOG_ERR("thread set stack size fail!");
        pthread_attr_destroy(&stThreadAttr);
        return iRet;
    }
    iRet = pthread_create(pstThreadId, &stThreadAttr, pThreadFunc, pTreadArg);
    if (RB_OK != iRet)
    {
        DBG_LOG_ERR("thread create pThreadFunc fail!");
        pthread_attr_destroy(&stThreadAttr);
        return iRet;
    }

    return iRet;
}

/**@brief     设置线程名称封装接口函数，开发中所有线程都必须通过该接口设置名称
* @param[in]  pTreadName:线程控名字
* @return     RB_OK:线程名字设置成功,RB_ERR:线程名字设置失败
*/
RB_INT32 rb_pthread_set_name(RB_INT8 *pTreadName)
{
    if ((RB_NULL == pTreadName) || (0 == strlen(pTreadName)))
    {
        DBG_LOG_ERR("set thread input pTreadName is NULL!");
        return RB_ERR;
    }
    
    prctl(PR_SET_NAME, pTreadName);
    
    return RB_OK;
}

/**@brief     线程销毁封装接口函数，开发中所有线程销毁都必须通过该接口
* @param[in]  无
* @return     RB_OK:执行成功，其他执行失败
*/
RB_INT32 rb_pthread_cancel(RB_VOID)
{
    RB_INT32 iRet = RB_ERR;
    pthread_t stThreadId;

    stThreadId = pthread_self();
    if (stThreadId > 0)
    {
        iRet = pthread_cancel(stThreadId);
    }
    
    return iRet;
}

/**@brief     线程消息封装接口函数，开发中所有线程销毁都必须通过该接口
* @param[in]  stThreadId:线程ID
* @param[out] pRetVal:线程销毁原因
* @return     RB_OK:执行成功，其他执行失败
*/
RB_INT32 rb_pthread_join(pthread_t stThreadId, RB_VOID *pRetVal)
{
    RB_INT32 iRet = RB_ERR;
    
    iRet = pthread_join(stThreadId, &pRetVal);
    
    return iRet;
}

